#ifndef _UTILS_HPP_
#define _UTILS_HPP_

#if defined(__SSE__)||defined(__MMX__)
#include "cpp/vectormath_aos.h"
#else
#include "cpp/vectormath_aos.h"
#endif

#include "testbedGL.hpp"

struct FrustumCallback
{
    void test();
};

struct Material
{
std::string name;
};

struct Heightmap
{
    Image img;
    void load(std::string file)
    {
        TestbedGL::load(file.c_str(),img);
    }
    float get_level(int x,int y)
    {
        unsigned char* ptr = (unsigned char*)&(img.data.get()[(x*257+y)*3]);
        return (ptr[0]*10.0f + ptr[1]*1 + ptr[2]*0.1f)*0.04f;

    }
    float get_height(int x,int,int detail);
};

struct Camera
{
	float pitch,yaw,bank;
    TestbedGL::Matrix4GL projection;
    TestbedGL::Matrix4GL modelview;
    TestbedGL::Matrix4GL mvp;

    Point3 pos;
    Vector3 lookAt;
    TestbedGL::Matrix4GL rotation;

    float length;

	void Perspective(float afov,float aaspect,float anear,float afar)
	{
		projection = Matrix4::perspective(afov,aaspect,anear,afar);
	}

	void Frustum(float aleft,float aright,float abottom,float atop,float anear,float afar)
	{
		projection = Matrix4::frustum(aleft,aright,abottom,atop,anear,afar);
	}

    void Move(Vector3 vec)
	{
		pos+=vec;
		modelview = Matrix4::lookAt(pos,pos+Vector3(lookAt),Vector3(0,1.0,0));
		mvp = projection * modelview;
	}

	Vector3 GetDir()
	{
			return Vector3(lookAt);
	}

	void SetEuler(float pitch,float yaw,float bank)
	{
        rotation = TestbedGL::euler_to_quat(pitch,yaw,bank);
		lookAt = Vector3(rotation.getElem(0,2),rotation.getElem(1,2),rotation.getElem(2,2));
		lookAt = normalize(lookAt);
		modelview = Matrix4::lookAt(Point3(pos),Point3(pos+lookAt),Vector3(0,1.0,0));
		mvp = projection * modelview;
	}

	void SetEuler3dPerson(float pitch,float yaw,float bank,float length)
	{
	}


    void RotateByMouse(float x,float y)
    {
            SetEuler(x,0,y);
    }

    void update()
    {
		modelview = Matrix4::lookAt(Point3(pos),Point3(pos+lookAt),Vector3(0,1.0,0));
		mvp = projection * modelview;
    }

    TestbedGL::Matrix4GL& getMVP()
    {

        return mvp;
    }

};

static float bias[16] =
{
    0.5, 0.0, 0.0, 0.0,
    0.0, 0.5, 0.0, 0.0,
    0.0, 0.0, 0.5, 0.0,
    0.5, 0.5, 0.5, 1.0
};

struct UniformShadowCamera:public Camera
{
Point3 lightPos,targetPos;
TestbedGL::Matrix4GL texMatrix;
UniformShadowCamera(){}
UniformShadowCamera(const Point3& lpos,const Point3 &tpos):lightPos(lpos),targetPos(tpos)
{}

void SetupLightMatrix(const Point3& lpos, const Point3& tpos)
{
    lightPos = lpos;
    targetPos = tpos;
	projection = Matrix4::perspective(45,0.5,10,50);
	modelview = Matrix4::lookAt(lightPos,targetPos,Vector3(0,1,0));
	mvp = projection * modelview;
}

void SetupTextureMatrix()
{

    texMatrix.set_matrix(bias);
    texMatrix *= projection;
    texMatrix *= modelview;

}

};

#endif
